﻿// <copyright file="LogicalExpressionHelper.cs" company="http://www.dymetis.com">
//
// Copyright (c) 2011 Eddie Z. Lin.
//
// This source is subject to the Microsoft Public License.
// See http://www.opensource.org/licenses/ms-pl.
// All other rights reserved.
// 
// </copyright>

namespace Dymetis.Expressions
{
    using System;
    using System.Reflection;
    using System.Text.RegularExpressions;

    internal static class LogicalExpressionHelper
    {
        private static readonly MethodInfo dateAddDaysMethod = typeof(LogicalExpressionHelper).GetMethod("DateAddDays");

        private static readonly MethodInfo dateSubstractDaysMethod = typeof(LogicalExpressionHelper).GetMethod("DateSubstractDays");

        private static readonly MethodInfo stringIsMatchMethod = typeof(LogicalExpressionHelper).GetMethod("StringIsMatch");

        private static readonly MethodInfo stringIsLikeMethod = typeof(LogicalExpressionHelper).GetMethod("StringIsLike");

        private static readonly MethodInfo stringIsUnderMethod = typeof(LogicalExpressionHelper).GetMethod("StringIsUnder");

        private static readonly MethodInfo dateGetDateMethod = typeof(LogicalExpressionHelper).GetMethod("DateGetDate");

        private static readonly MethodInfo changeTypeMethod = typeof(LogicalExpressionHelper).GetMethod("ChangeType");

        private static readonly MethodInfo objectEqualMethod = typeof(LogicalExpressionHelper).GetMethod("ObjectEqual");

        private static readonly MethodInfo objectLessThanMethod = typeof(LogicalExpressionHelper).GetMethod("ObjectLessThan");

        private static readonly MethodInfo objectLessThanEqualMethod = typeof(LogicalExpressionHelper).GetMethod("ObjectLessThanEqual");

        private static readonly MethodInfo objectGreaterThanMethod = typeof(LogicalExpressionHelper).GetMethod("ObjectGreaterThan");

        private static readonly MethodInfo objectNotEqualMethod = typeof(LogicalExpressionHelper).GetMethod("ObjectNotEqual");

        private static readonly MethodInfo objectGreaterThanEqualMethod = typeof(LogicalExpressionHelper).GetMethod("ObjectGreaterThanEqual");

        public static MethodInfo ObjectLessThanMethod
        {
            get 
            { 
                return LogicalExpressionHelper.objectLessThanMethod; 
            }
        }

        public static MethodInfo ObjectLessThanEqualMethod
        {
            get 
            { 
                return LogicalExpressionHelper.objectLessThanEqualMethod; 
            }
        }

        public static MethodInfo ObjectGreaterThanMethod
        {
            get
            {
                return LogicalExpressionHelper.objectGreaterThanMethod; 
            }
        }

        public static MethodInfo ObjectNotEqualMethod
        {
            get
            {
                return LogicalExpressionHelper.objectNotEqualMethod;
            }
        }

        public static MethodInfo ObjectGreaterThanEqualMethod
        {
            get
            {
                return LogicalExpressionHelper.objectGreaterThanEqualMethod;
            }
        } 

        public static MethodInfo ObjectEqualMethod
        {
            get
            {
                return LogicalExpressionHelper.objectEqualMethod;
            }
        } 

        public static MethodInfo ChangeTypeMethod
        {
            get
            {
                return LogicalExpressionHelper.changeTypeMethod; 
            }
        } 

        public static MethodInfo DateAddDaysMethod
        {
            get
            {
                return LogicalExpressionHelper.dateAddDaysMethod;
            }
        }

        public static MethodInfo DateSubstractDaysMethod
        {
            get
            {
                return LogicalExpressionHelper.dateSubstractDaysMethod;
            }
        }

        public static MethodInfo StringIsMatchMethod
        {
            get
            {
                return LogicalExpressionHelper.stringIsMatchMethod;
            }
        }

        public static MethodInfo StringIsLikeMethod
        {
            get
            {
                return LogicalExpressionHelper.stringIsLikeMethod;
            }
        }

        public static MethodInfo StringIsUnderMethod
        {
            get
            {
                return LogicalExpressionHelper.stringIsUnderMethod;
            }
        }

        public static MethodInfo DateGetDateMethod
        {
            get
            {
                return LogicalExpressionHelper.dateGetDateMethod;
            }
        }

        public static DateTime DateGetDate()
        {
            return DateTime.Now;
        }

        public static DateTime DateAddDays(DateTime source, long days)
        {
            return source.AddDays(days);
        }

        public static DateTime DateSubstractDays(DateTime source, long days)
        {
            return source.AddDays(-days);
        }

        public static bool StringIsMatch(object inputObj, object patternObj)
        {
            var input = inputObj as string;
            var pattern = patternObj as string;
            return Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase);
        }

        public static bool StringIsLike(object inputObj, object patternObj)
        {
            var input = inputObj as string;
            var pattern = patternObj as string;
            return Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase);
        }

        public static bool StringIsUnder(object inputObj, object targetObj)
        {
            var input = inputObj as string;
            var target = targetObj as string;

            string[] inputArray = input.Split(new char[] { '\n', ';' });
            string[] targetArray = target.Split(new char[] { '\n', ';' });
            foreach (string inputElement in inputArray)
            {
                foreach (string targetElement in targetArray)
                {
                    if (inputElement.Trim().ToUpperInvariant().StartsWith(targetElement.ToUpperInvariant(), StringComparison.CurrentCultureIgnoreCase))
                    {
                        return true;
                    }
                }
            }

            return false;
        }

        public static bool ObjectLessThan(object a, object b)
        {
            return ObjectCompare(a, b) < 0;
        }

        public static bool ObjectLessThanEqual(object a, object b)
        {
            return ObjectCompare(a, b) <= 0;
        }

        public static bool ObjectGreaterThan(object a, object b)
        {
            return ObjectCompare(a, b) > 0;
        }

        public static bool ObjectGreaterThanEqual(object a, object b)
        {
            return ObjectCompare(a, b) >= 0;
        }

        public static bool ObjectNotEqual(object a, object b)
        {
            return !ObjectEqual(a, b);
        }

        public static bool ObjectEqual(object a, object b)
        {
            if (a == null && b == null)
            {
                return true;
            }

            if (a != null && b != null)
            {
                return ((dynamic)a) == ((dynamic)b);
            }

            return true;
        }

        public static T ChangeType<T, TSource>(TSource value)
            where TSource : T
        {
            return (T)value;
        }

        private static int ObjectCompare(object a, object b)
        {
            if (a == null && b == null)
            {
                return 0;
            }

            IComparable comparable;

            if ((comparable = a as IComparable) != null)
            {
                return comparable.CompareTo(b);
            }

            if ((comparable = b as IComparable) != null)
            {
                return comparable.CompareTo(a);
            }

            throw new Exception(String.Format("Can not compare '{0}' with '{1}'.", a, b));
        }
    }
}
